package com.bank.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.bank.dto.Result;
import com.bank.entity.CardInfo;
import com.bank.entity.TradeInfo;
import com.bank.exception.BankException;
import com.bank.mapper.CardInfoMapper;
import com.bank.mapper.TradeInfoMapper;
import com.bank.service.CardInfoService;
import com.bank.service.TradeInfoService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVPrinter;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.io.StringWriter;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

/**
 * 交易信息服务实现类
 * 实现交易信息相关的业务逻辑处理
 * 
 * @author 开发团队
 * @version 1.0.0
 * @since 2025-06-19
 */
@Slf4j
@Service
@Transactional(rollbackFor = Exception.class)
public class TradeInfoServiceImpl implements TradeInfoService {

    @Autowired
    private TradeInfoMapper tradeInfoMapper;

    @Autowired
    private CardInfoMapper cardInfoMapper;

    @Autowired
    private CardInfoService cardInfoService;

    /**
     * 银行卡号正则表达式
     */
    private static final Pattern CARD_ID_PATTERN = Pattern.compile("^[0-9]{16}$");

    @Override
    public Result<TradeInfo> addTrade(TradeInfo tradeInfo) {
        log.info("开始新增交易记录：{}", tradeInfo);
        
        try {
            // 验证交易信息
            Result<Void> validateResult = validateTradeInfo(tradeInfo);
            if (!validateResult.isSuccess()) {
                return Result.error(validateResult.getMessage());
            }

            // 插入交易记录
            int result = tradeInfoMapper.insert(tradeInfo);
            if (result > 0) {
                log.info("交易记录新增成功，交易ID：{}", tradeInfo.getTradeId());
                return Result.success("交易记录新增成功", tradeInfo);
            } else {
                return Result.error("交易记录新增失败");
            }
        } catch (Exception e) {
            log.error("新增交易记录异常：", e);
            throw new BankException("新增交易记录失败：" + e.getMessage());
        }
    }

    @Override
    public Result<String> deleteTrade(Integer tradeId) {
        log.info("开始删除交易记录，交易ID：{}", tradeId);
        
        try {
            if (tradeId == null) {
                return Result.badRequest("交易ID不能为空");
            }

            // 检查交易记录是否存在
            TradeInfo tradeInfo = tradeInfoMapper.selectById(tradeId);
            if (tradeInfo == null) {
                return Result.notFound("交易记录不存在");
            }

            // 删除交易记录
            int result = tradeInfoMapper.deleteById(tradeId);
            if (result > 0) {
                log.info("交易记录删除成功，交易ID：{}", tradeId);
                return Result.success("交易记录删除成功");
            } else {
                return Result.error("交易记录删除失败");
            }
        } catch (Exception e) {
            log.error("删除交易记录异常：", e);
            throw new BankException("删除交易记录失败：" + e.getMessage());
        }
    }

    @Override
    public Result<String> batchDeleteTrades(List<Integer> tradeIds) {
        log.info("开始批量删除交易记录，交易ID列表：{}", tradeIds);
        
        try {
            if (tradeIds == null || tradeIds.isEmpty()) {
                return Result.badRequest("交易ID列表不能为空");
            }

            // 批量删除交易记录
            int result = tradeInfoMapper.batchDeleteByIds(tradeIds);
            if (result > 0) {
                log.info("批量删除交易记录成功，删除数量：{}", result);
                return Result.success("批量删除交易记录成功，删除数量：" + result);
            } else {
                return Result.error("批量删除交易记录失败");
            }
        } catch (Exception e) {
            log.error("批量删除交易记录异常：", e);
            throw new BankException("批量删除交易记录失败：" + e.getMessage());
        }
    }

    @Override
    @Transactional(readOnly = true)
    public Result<TradeInfo> getTradeById(Integer tradeId) {
        try {
            if (tradeId == null) {
                return Result.badRequest("交易ID不能为空");
            }

            TradeInfo tradeInfo = tradeInfoMapper.selectById(tradeId);
            if (tradeInfo == null) {
                return Result.notFound("交易记录不存在");
            }

            return Result.success(tradeInfo);
        } catch (Exception e) {
            log.error("查询交易记录异常：", e);
            throw new BankException("查询交易记录失败：" + e.getMessage());
        }
    }

    @Override
    @Transactional(readOnly = true)
    public Result<List<TradeInfo>> getTradesByCardId(String cardId) {
        try {
            if (StringUtils.isBlank(cardId)) {
                return Result.badRequest("银行卡号不能为空");
            }

            List<TradeInfo> tradeInfoList = tradeInfoMapper.selectByCardId(cardId);
            return Result.success(tradeInfoList);
        } catch (Exception e) {
            log.error("根据卡号查询交易记录异常：", e);
            throw new BankException("查询交易记录失败：" + e.getMessage());
        }
    }

    @Override
    @Transactional(readOnly = true)
    public Result<List<TradeInfo>> getTradesByType(String tradeType) {
        try {
            if (StringUtils.isBlank(tradeType)) {
                return Result.badRequest("交易类型不能为空");
            }

            List<TradeInfo> tradeInfoList = tradeInfoMapper.selectByTradeType(tradeType);
            return Result.success(tradeInfoList);
        } catch (Exception e) {
            log.error("根据交易类型查询交易记录异常：", e);
            throw new BankException("查询交易记录失败：" + e.getMessage());
        }
    }

    @Override
    @Transactional(readOnly = true)
    public Result<List<TradeInfo>> getTradesByTimeRange(LocalDateTime startTime, LocalDateTime endTime) {
        try {
            if (startTime == null || endTime == null) {
                return Result.badRequest("开始时间和结束时间不能为空");
            }

            if (startTime.isAfter(endTime)) {
                return Result.badRequest("开始时间不能晚于结束时间");
            }

            List<TradeInfo> tradeInfoList = tradeInfoMapper.selectByTradeTimeRange(startTime, endTime);
            return Result.success(tradeInfoList);
        } catch (Exception e) {
            log.error("根据交易时间范围查询异常：", e);
            throw new BankException("查询交易记录失败：" + e.getMessage());
        }
    }

    @Override
    @Transactional(readOnly = true)
    public Result<List<TradeInfo>> getTradesByAmountRange(BigDecimal minAmount, BigDecimal maxAmount) {
        try {
            if (minAmount == null || maxAmount == null) {
                return Result.badRequest("最小金额和最大金额不能为空");
            }

            if (minAmount.compareTo(maxAmount) > 0) {
                return Result.badRequest("最小金额不能大于最大金额");
            }

            List<TradeInfo> tradeInfoList = tradeInfoMapper.selectByAmountRange(minAmount, maxAmount);
            return Result.success(tradeInfoList);
        } catch (Exception e) {
            log.error("根据交易金额范围查询异常：", e);
            throw new BankException("查询交易记录失败：" + e.getMessage());
        }
    }

    @Override
    @Transactional(readOnly = true)
    public Result<IPage<TradeInfo>> getTradesPage(Page<TradeInfo> page, String cardId, String customerName, String tradeType,
                                                 LocalDateTime startTime, LocalDateTime endTime,
                                                 BigDecimal minAmount, BigDecimal maxAmount) {
        try {
            if (startTime != null && endTime != null && startTime.isAfter(endTime)) {
                return Result.badRequest("开始时间不能晚于结束时间");
            }

            if (minAmount != null && maxAmount != null && minAmount.compareTo(maxAmount) > 0) {
                return Result.badRequest("最小金额不能大于最大金额");
            }

            IPage<TradeInfo> result = tradeInfoMapper.selectPageWithConditions(page, cardId, customerName, tradeType,
                    startTime, endTime, minAmount, maxAmount);
            return Result.success(result);
        } catch (Exception e) {
            log.error("分页查询交易记录异常：", e);
            throw new BankException("查询交易记录失败：" + e.getMessage());
        }
    }

    @Override
    @Transactional(readOnly = true)
    public Result<IPage<TradeInfo>> getTradesPageByCardId(Page<TradeInfo> page, String cardId, String password,
                                                         String tradeType, LocalDateTime startTime, LocalDateTime endTime) {
        try {
            if (StringUtils.isBlank(cardId)) {
                return Result.badRequest("银行卡号不能为空");
            }

            if (StringUtils.isBlank(password)) {
                return Result.badRequest("密码不能为空");
            }

            // 验证密码
            Result<Boolean> validateResult = cardInfoService.validatePassword(cardId, password);
            if (!validateResult.getData()) {
                return Result.error("密码错误");
            }

            if (startTime != null && endTime != null && startTime.isAfter(endTime)) {
                return Result.badRequest("开始时间不能晚于结束时间");
            }

            IPage<TradeInfo> result = tradeInfoMapper.selectPageByCardId(page, cardId, tradeType, startTime, endTime);
            return Result.success(result);
        } catch (Exception e) {
            log.error("根据卡号分页查询交易记录异常：", e);
            throw new BankException("查询交易记录失败：" + e.getMessage());
        }
    }

    @Override
    public Result<String> transfer(String fromCardId, String fromPassword, String toCardId, BigDecimal amount, String remark) {
        log.info("开始转账操作，转出卡号：{}，转入卡号：{}，金额：{}", fromCardId, toCardId, amount);

        try {
            if (StringUtils.isBlank(fromCardId)) {
                return Result.badRequest("转出银行卡号不能为空");
            }

            if (StringUtils.isBlank(fromPassword)) {
                return Result.badRequest("转出银行卡密码不能为空");
            }

            if (StringUtils.isBlank(toCardId)) {
                return Result.badRequest("转入银行卡号不能为空");
            }

            if (amount == null || amount.compareTo(BigDecimal.ZERO) <= 0) {
                return Result.badRequest("转账金额必须大于0");
            }

            if (fromCardId.equals(toCardId)) {
                return Result.badRequest("转出卡号和转入卡号不能相同");
            }

            // 验证转出卡密码
            Result<Boolean> validateResult = cardInfoService.validatePassword(fromCardId, fromPassword);
            if (!validateResult.getData()) {
                return Result.error("转出银行卡密码错误");
            }

            // 检查转出卡是否存在且未挂失
            CardInfo fromCard = cardInfoMapper.selectById(fromCardId);
            if (fromCard == null) {
                return Result.notFound("转出银行卡不存在");
            }

            if (fromCard.getIsReportLoss()) {
                return Result.error("转出银行卡已挂失，无法进行转账操作");
            }

            // 检查转入卡是否存在且未挂失
            CardInfo toCard = cardInfoMapper.selectById(toCardId);
            if (toCard == null) {
                return Result.notFound("转入银行卡不存在");
            }

            if (toCard.getIsReportLoss()) {
                return Result.error("转入银行卡已挂失，无法进行转账操作");
            }

            // 调用转账存储过程
            Integer result = tradeInfoMapper.callTransferProcedure(fromCardId, toCardId, amount, remark);
            if (result != null && result == 0) {
                log.info("转账操作成功，转出卡号：{}，转入卡号：{}，金额：{}", fromCardId, toCardId, amount);
                return Result.success("转账成功");
            } else {
                return Result.error("转账失败，请检查余额是否充足");
            }
        } catch (Exception e) {
            log.error("转账操作异常：", e);
            throw new BankException("转账失败：" + e.getMessage());
        }
    }

    @Override
    @Transactional(readOnly = true)
    public Result<Map<String, Object>> getTradeStatistics() {
        try {
            Map<String, Object> statistics = new HashMap<>();
            statistics.put("totalCount", tradeInfoMapper.selectTotalCount());
            statistics.put("depositCount", tradeInfoMapper.countByTradeType(TradeInfo.TradeType.DEPOSIT));
            statistics.put("withdrawCount", tradeInfoMapper.countByTradeType(TradeInfo.TradeType.WITHDRAW));
            statistics.put("transferCount", tradeInfoMapper.countByTradeType(TradeInfo.TradeType.TRANSFER));
            statistics.put("depositAmount", tradeInfoMapper.sumAmountByTradeType(TradeInfo.TradeType.DEPOSIT));
            statistics.put("withdrawAmount", tradeInfoMapper.sumAmountByTradeType(TradeInfo.TradeType.WITHDRAW));
            statistics.put("transferAmount", tradeInfoMapper.sumAmountByTradeType(TradeInfo.TradeType.TRANSFER));

            return Result.success(statistics);
        } catch (Exception e) {
            log.error("获取交易统计信息异常：", e);
            throw new BankException("获取交易统计信息失败：" + e.getMessage());
        }
    }

    @Override
    @Transactional(readOnly = true)
    public Result<Integer> getTradeCountByType(String tradeType) {
        try {
            if (StringUtils.isBlank(tradeType)) {
                return Result.badRequest("交易类型不能为空");
            }

            int count = tradeInfoMapper.countByTradeType(tradeType);
            return Result.success(count);
        } catch (Exception e) {
            log.error("根据交易类型统计交易数量异常：", e);
            throw new BankException("统计交易数量失败：" + e.getMessage());
        }
    }

    @Override
    @Transactional(readOnly = true)
    public Result<BigDecimal> getTradeAmountByType(String tradeType) {
        try {
            if (StringUtils.isBlank(tradeType)) {
                return Result.badRequest("交易类型不能为空");
            }

            BigDecimal amount = tradeInfoMapper.sumAmountByTradeType(tradeType);
            return Result.success(amount != null ? amount : BigDecimal.ZERO);
        } catch (Exception e) {
            log.error("根据交易类型统计交易金额异常：", e);
            throw new BankException("统计交易金额失败：" + e.getMessage());
        }
    }

    @Override
    @Transactional(readOnly = true)
    public Result<List<Map<String, Object>>> getTradeStatisticsByTimeRange(LocalDateTime startTime, LocalDateTime endTime) {
        try {
            if (startTime == null || endTime == null) {
                return Result.badRequest("开始时间和结束时间不能为空");
            }

            if (startTime.isAfter(endTime)) {
                return Result.badRequest("开始时间不能晚于结束时间");
            }

            List<Map<String, Object>> statistics = tradeInfoMapper.selectTradeStatistics(startTime, endTime);
            return Result.success(statistics);
        } catch (Exception e) {
            log.error("获取指定时间范围内的交易统计异常：", e);
            throw new BankException("获取交易统计失败：" + e.getMessage());
        }
    }

    @Override
    @Transactional(readOnly = true)
    public Result<List<Map<String, Object>>> getMonthlyTradeStatistics(Integer year, Integer month) {
        try {
            if (year == null || month == null) {
                return Result.badRequest("年份和月份不能为空");
            }

            if (month < 1 || month > 12) {
                return Result.badRequest("月份必须在1-12之间");
            }

            List<Map<String, Object>> statistics = tradeInfoMapper.selectMonthlyStatistics(year, month);
            return Result.success(statistics);
        } catch (Exception e) {
            log.error("获取月度交易汇总统计异常：", e);
            throw new BankException("获取月度统计失败：" + e.getMessage());
        }
    }

    @Override
    @Transactional(readOnly = true)
    public Result<List<Map<String, Object>>> getCardTradeAmountStatistics(LocalDateTime startTime, LocalDateTime endTime) {
        try {
            if (startTime == null || endTime == null) {
                return Result.badRequest("开始时间和结束时间不能为空");
            }

            if (startTime.isAfter(endTime)) {
                return Result.badRequest("开始时间不能晚于结束时间");
            }

            List<Map<String, Object>> statistics = tradeInfoMapper.selectCardTradeAmountStatistics(startTime, endTime);
            return Result.success(statistics);
        } catch (Exception e) {
            log.error("获取银行卡交易额统计异常：", e);
            throw new BankException("获取银行卡交易额统计失败：" + e.getMessage());
        }
    }

    @Override
    @Transactional(readOnly = true)
    public Result<String> exportTradesToCSV(LocalDateTime startTime, LocalDateTime endTime) {
        try {
            List<TradeInfo> tradeInfoList;
            if (startTime != null && endTime != null) {
                if (startTime.isAfter(endTime)) {
                    return Result.badRequest("开始时间不能晚于结束时间");
                }
                tradeInfoList = tradeInfoMapper.selectByTradeTimeRange(startTime, endTime);
            } else {
                tradeInfoList = tradeInfoMapper.selectList(null);
            }

            StringWriter stringWriter = new StringWriter();
            CSVFormat csvFormat = CSVFormat.DEFAULT.withHeader(
                "交易ID", "卡号", "交易日期", "交易类型", "交易金额", "目标卡号", "备注"
            );

            try (CSVPrinter csvPrinter = new CSVPrinter(stringWriter, csvFormat)) {
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

                for (TradeInfo tradeInfo : tradeInfoList) {
                    csvPrinter.printRecord(
                        tradeInfo.getTradeId(),
                        tradeInfo.getCardId(),
                        tradeInfo.getTradeDate() != null ? tradeInfo.getTradeDate().format(formatter) : "",
                        tradeInfo.getTradeType(),
                        tradeInfo.getTradeMoney(),
                        tradeInfo.getTargetCardId(),
                        tradeInfo.getRemark()
                    );
                }
            }

            log.info("交易记录导出成功，导出数量：{}", tradeInfoList.size());
            return Result.success("交易记录导出成功", stringWriter.toString());
        } catch (IOException e) {
            log.error("导出交易记录到CSV异常：", e);
            throw new BankException("导出交易记录失败：" + e.getMessage());
        }
    }

    @Override
    @Transactional(readOnly = true)
    public Result<String> exportTradeStatisticsToCSV(LocalDateTime startTime, LocalDateTime endTime) {
        try {
            if (startTime == null || endTime == null) {
                return Result.badRequest("开始时间和结束时间不能为空");
            }

            if (startTime.isAfter(endTime)) {
                return Result.badRequest("开始时间不能晚于结束时间");
            }

            List<Map<String, Object>> cardStatistics = tradeInfoMapper.selectCardTradeAmountStatistics(startTime, endTime);

            StringWriter stringWriter = new StringWriter();
            CSVFormat csvFormat = CSVFormat.DEFAULT.withHeader(
                "卡号", "客户姓名", "交易笔数", "存款金额", "取款金额", "转账金额", "总交易金额"
            );

            try (CSVPrinter csvPrinter = new CSVPrinter(stringWriter, csvFormat)) {
                for (Map<String, Object> stat : cardStatistics) {
                    csvPrinter.printRecord(
                        stat.get("cardId"),
                        stat.get("customerName"),
                        stat.get("tradeCount"),
                        stat.get("depositAmount"),
                        stat.get("withdrawAmount"),
                        stat.get("transferAmount"),
                        stat.get("totalAmount")
                    );
                }
            }

            log.info("交易统计报表导出成功，导出数量：{}", cardStatistics.size());
            return Result.success("交易统计报表导出成功", stringWriter.toString());
        } catch (IOException e) {
            log.error("导出交易统计报表到CSV异常：", e);
            throw new BankException("导出交易统计报表失败：" + e.getMessage());
        }
    }

    @Override
    public Result<Void> validateTradeInfo(TradeInfo tradeInfo) {
        if (tradeInfo == null) {
            return Result.badRequest("交易信息不能为空");
        }

        if (StringUtils.isBlank(tradeInfo.getCardId())) {
            return Result.badRequest("银行卡号不能为空");
        }

        if (!CARD_ID_PATTERN.matcher(tradeInfo.getCardId()).matches()) {
            return Result.badRequest("银行卡号格式不正确，应为16位数字");
        }

        if (StringUtils.isBlank(tradeInfo.getTradeType())) {
            return Result.badRequest("交易类型不能为空");
        }

        if (!TradeInfo.TradeType.DEPOSIT.equals(tradeInfo.getTradeType()) &&
            !TradeInfo.TradeType.WITHDRAW.equals(tradeInfo.getTradeType()) &&
            !TradeInfo.TradeType.TRANSFER.equals(tradeInfo.getTradeType())) {
            return Result.badRequest("交易类型只能是：存入、支取、转账");
        }

        if (tradeInfo.getTradeMoney() == null || tradeInfo.getTradeMoney().compareTo(BigDecimal.ZERO) <= 0) {
            return Result.badRequest("交易金额必须大于0");
        }

        if (StringUtils.isNotBlank(tradeInfo.getRemark()) && tradeInfo.getRemark().length() > 200) {
            return Result.badRequest("备注信息长度不能超过200个字符");
        }

        if (StringUtils.isNotBlank(tradeInfo.getTargetCardId()) &&
            !CARD_ID_PATTERN.matcher(tradeInfo.getTargetCardId()).matches()) {
            return Result.badRequest("目标卡号格式不正确，应为16位数字");
        }

        return Result.success();
    }
}
